home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / wzun11sr.zip / MAPNAME.C < prev    next >
Text File  |  1991-09-27  |  13KB  |  305 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   mapname.c
  4.  
  5.   This routine changes DEC-20, VAX/VMS, and DOS-style filenames into normal
  6.   Unix names (and vice versa, in some cases); it also creates any necessary 
  7.   directories, if the -d switch was specified.
  8.  
  9.   ---------------------------------------------------------------------------
  10.  
  11.   Action:  renames argument files as follows:
  12.  
  13.      strips Unix and PKZIP DOS path name from front (up to rightmost '/') if
  14.        present.
  15.      strips DEC device:, node:: names from front (up to rightmost ':') if
  16.        present.  (This also takes care of any DOS drive: artifacts.)
  17.      strips DEC-20 <directory> or VMS [directory] name if present.
  18.      strips DEC-20 version number from end (everything after 2nd dot) if
  19.        present.
  20.      strips VMS generation number from end (everything after ';') if present,
  21.        unless "-V" switch specified.
  22.      honors DEC-20 CTRL-V quote for special characters.
  23.      discards unquoted unprintable characters.
  24.      [VMS] converts Unix-style pathnames to VMS style.
  25.  
  26.      Returns 0 if no error, 1 if filename truncated, 2 for any other error.
  27.  
  28.   ---------------------------------------------------------------------------
  29.  
  30.   Author:  David Kirschbaum, 25 Apr 90
  31.      (Based on good old xxu.c by Frank da Cruz, CUCCA)
  32.      Subsequent tweaks by Bill Davidsen, James Dugal, Larry Jones,
  33.      Mark Edwards, Greg Roelofs, Antoine Verheijen.
  34.  
  35.   ---------------------------------------------------------------------------
  36.  
  37.   Notes:
  38.  
  39.      - Unix allows multiple dots in directory names; MS-DOS and OS/2 FAT
  40.        allow one; VMS does not allow any.  Things are almost as bad with
  41.        regular filenames (VMS allows a single dot but TOPS-20 allows two,
  42.        if you count the one in front of the version number).  As of v4.04,
  43.        mapname converts directory-name dots to underscores on VMS, but it
  44.        otherwise leaves the dots alone.  Since it is now possible to create
  45.        zipfiles under Unix, this whole routine pretty much needs to be
  46.        rewritten (different routines for each output OS, and different 
  47.        rules for different parts of the path name).
  48.      - If each zip program stores local-format names (like the VMS one did
  49.        at one time), it would probably be best to convert to an intermedi-
  50.        ate format first (assuming we're not extracting under the same OS 
  51.        as that under which the zipfile was created), then from that to the 
  52.        current operating system's format.
  53.      - The strcpy and strcat operations on both cdp and filename may over-
  54.        write memory, since they don't check lengths.  With a kilobyte in
  55.        which to work, this is probably not that big a deal, but it could
  56.        cause problems eventually.
  57.  
  58.   ------------------------------------------------------------------------- */
  59.  
  60.  
  61. #include "unzip.h"
  62.  
  63.  
  64. /********************/
  65. /*  Mapname Defines */
  66. /********************/
  67.  
  68. #ifdef VMS
  69. #define PERMS   0
  70. #else
  71. #define PERMS   0777
  72. #endif
  73.  
  74. #ifndef NO_MKDIR
  75. #ifdef DOS_OS2
  76. #if (_MSC_VER >= 600)           /* have special MSC mkdir prototype */
  77. #include <direct.h>
  78. #else                           /* own prototype because dir.h conflicts?? */
  79. int mkdir(const char *path);
  80. #endif                          /* !(MSC 6.0 or later) */
  81. #define MKDIR(path,mode)   mkdir(path)
  82. #else                           /* !DOS_OS2 */
  83. #define MKDIR(path,mode)   mkdir(path,mode)
  84. #endif
  85. #endif                          /* !NO_MKDIR */
  86.  
  87. /***************************/
  88. /*  Function mapped_name() */
  89. /***************************/
  90.  
  91. mapped_name()
  92. {
  93. #ifdef NO_MKDIR
  94.     char command[FILNAMSIZ+40]; /* buffer for system() call */
  95. #endif
  96. #ifdef VMS
  97.     int stat_val;               /* temp. holder for stat() return value */
  98.     char *dp, *xp;              /* ptrs to directory name */
  99. #endif
  100.     char name[FILNAMSIZ];       /* file name buffer */
  101.     char *pp, *cp, *cdp;        /* character pointers */
  102.     char delim = '\0';          /* Directory Delimiter */
  103.     int dc = 0;                 /* Counters */
  104.     int quote = FALSE;          /* Flags */
  105.     int indir = FALSE;
  106.     int done = FALSE;
  107.     register int workch;        /* hold the character being tested */
  108.  
  109.  
  110.  
  111. /*---------------------------------------------------------------------------
  112.     Initialize various pointers and counters and stuff.
  113.   ---------------------------------------------------------------------------*/
  114.  
  115. #ifdef MAP_DEBUG
  116.     fprintf(stderr, "%s ", filename);   /* echo name of this file */
  117. #endif
  118.     pp = name;                  /* Point to translation buffer */
  119.     *name = '\0';               /* Initialize buffer */
  120.  
  121.     if (dflag) {                /* -d => retain directory structure */
  122.         cdp = (char *) malloc(strlen(filename) + 3);  /* place for */
  123.         if (cdp == NULL) {      /*   holding directory name */
  124.             fprintf(stderr, "malloc failed in conversion of [%s]\n", filename);
  125.             return (2);
  126.         }
  127. #ifdef VMS
  128.         *cdp++ = '[';
  129.         xp = cdp;               /* always points to last non-NULL char */
  130.         *cdp++ = '.';
  131. #endif
  132. #ifdef MACOS
  133.         *cdp = ':';             /* the Mac uses ':' as a directory separator */
  134.         cdp[1] = '\0';
  135. #else
  136.         *cdp = '\0';
  137. #endif
  138.     }
  139.     dc = 0;                     /* Filename dot counter */
  140.  
  141. /*---------------------------------------------------------------------------
  142.     Begin main loop through characters in filename.
  143.   ---------------------------------------------------------------------------*/
  144.  
  145.     for (cp = filename; (workch = *cp++) != 0  &&  !done;) {
  146.  
  147.         if (quote) {            /* If this char quoted... */
  148.             *pp++ = workch;     /*  include it literally. */
  149.             quote = FALSE;
  150.         } else if (indir) {     /* If in directory name... */
  151.             if (workch == delim)
  152.                 indir = FALSE;  /*  look for end delimiter. */
  153.         } else
  154.             switch (workch) {
  155.             case '<':           /* Discard DEC-20 directory name */
  156.                 indir = TRUE;
  157.                 delim = '>';
  158.                 break;
  159.             case '[':           /* Discard VMS directory name */
  160.                 indir = TRUE;
  161.                 delim = ']';
  162.                 break;
  163.             case '/':           /* Discard Unix path name... */
  164.             case '\\':          /*  or MS-DOS path name...
  165.                                  *  UNLESS -d flag was given. */
  166.                 /*
  167.                  * Special processing case:  if -d flag was specified on
  168.                  * command line, create any necessary directories included
  169.                  * in the pathname.  Creation of directories is straight-
  170.                  * forward on BSD and MS-DOS machines but requires use of
  171.                  * the system() command on SysV systems (or any others which
  172.                  * don't have mkdir()).  The stat() check is necessary with
  173.                  * MSC because it doesn't have an EEXIST errno, and it saves
  174.                  * the overhead of multiple system() calls on SysV machines.
  175.                  */
  176.  
  177.                 if (dflag) {
  178.                     *pp = '\0';
  179. #ifdef VMS
  180.                     dp = name;
  181.                     while (*++xp = *dp++)   /* copy name to cdp, while */
  182.                         if (*xp == '.')     /*   changing all dots... */
  183.                             *xp = '_';      /*   ...to underscores */
  184.                     strcpy(xp, ".dir");    /* add extension for stat check */
  185.                     stat_val = stat(cdp, &statbuf);
  186.                     *xp = '\0';         /* remove extension for all else */
  187.                     if (stat_val) {     /* doesn't exist, so create */
  188. #else
  189.                     strcat(cdp, name);
  190.                     if (stat(cdp, &statbuf)) {  /* doesn't exist, so create */
  191. #endif
  192. #ifdef NO_MKDIR
  193.                         sprintf(command, "IFS=\" \t\n\" /bin/mkdir %s 2>/dev/null", cdp);
  194.                         if (system(command)) {
  195. #else
  196.                         if (MKDIR(cdp, PERMS) == -1) {
  197. #endif
  198.                             perror(cdp);
  199.                             free(cdp);
  200.                             fprintf(stderr, "Unable to process [%s]\n", filename);
  201.                             return (2);
  202.                         }
  203.                     } else if (!(statbuf.st_mode & S_IFDIR)) {
  204.                         fprintf(stderr, "%s:  exists but is not a directory\n",
  205.                                 cdp);
  206.                         free(cdp);
  207.                         fprintf(stderr, "unable to process [%s]\n", filename);
  208.                         return (2);
  209.                     }
  210. #ifdef VMS
  211.                     *xp = '/';  /* for now... (mkdir()) */
  212. #else /* !VMS */
  213. #ifdef MACOS
  214.                     strcat(cdp, ":");
  215. #else /* !MACOS */
  216.                     strcat(cdp, "/");
  217. #endif /* ?MACOS */
  218. #endif /* ?VMS */
  219.                 }               /***** FALL THROUGH to ':' case  **** */
  220.             case ':':           /* Discard DEC dev: or node:: name */
  221.                 pp = name;
  222.                 break;
  223.             case '.':                   /* DEC-20 generation number
  224.                                          * or MS-DOS type */
  225. #ifdef NUKE_DOTS
  226.                 if (++dc == 1)          /* Keep first dot */
  227.                     *pp++ = workch;
  228. #else
  229.                 ++dc;                   /* Not used, but what the hell. */
  230.                 *pp++ = workch;
  231. #endif
  232.                 break;
  233.             case ';':                   /* VMS generation or DEC-20 attrib */
  234.                 if (V_flag)             /* If requested, save VMS ";##" */
  235.                     *pp++ = workch;     /*  version info; else discard */
  236.                 else                    /*  everything starting with */
  237.                     done = TRUE;        /*  semicolon.  (Worry about */
  238.                 break;                  /*  DEC-20 later.) */
  239.             case '\026':                /* Control-V quote for special chars */
  240.                 quote = TRUE;           /* Set flag for next time. */
  241.                 break;
  242.             default:                    /* some other char */
  243.                 if (isdigit(workch))    /* '0'..'9' */
  244.                     *pp++ = workch;     /* accept them, no tests */
  245.                 else {
  246.                     if (workch == ' ')  /* change blanks to underscore */
  247.                         *pp++ = '_';
  248.                     else if (isprint(workch))   /* Other printable, just keep */
  249.                         *pp++ = workch;
  250.                 }
  251.             }                   /* switch */
  252.     }                           /* for loop */
  253.     *pp = '\0';                 /* Done with name, terminate it */
  254.  
  255. /*---------------------------------------------------------------------------
  256.     We COULD check for existing names right now, create a "unique" name, etc.
  257.     However, since other unzips don't do that...we won't bother.  Maybe an-
  258.     other day, ne?  If this went bad, the name'll either be nulled out (in
  259.     which case we'll return non-0) or following procedures won't be able to
  260.     create the extracted file, and other error msgs will result.
  261.   ---------------------------------------------------------------------------*/
  262.  
  263.     if (*name == '\0') {
  264.         fprintf(stderr, "conversion of [%s] failed\n", filename);
  265.         return (2);
  266.     }
  267.     if (dflag) {
  268. #ifdef VMS
  269.         *xp++ = ']';            /* proper end-of-dir-name delimiter */
  270.         if (xp == cdp) {        /* no path-name stuff, so... */
  271.             strcpy(filename, name);  /* copy file name into global */
  272.             cdp -= 2;           /*   prepare to free malloc'd space */
  273.         } else {                /* we've added path-name stuff... */
  274.             *xp = '\0';         /*   so terminate... */
  275.             dp = cdp;           /*   and convert to VMS subdir separators:  */
  276.             while (*++dp)       /*   (skip first char:  better not be "/") */
  277.                 if (*dp == '/') /*   change all slashes */
  278.                     *dp = '.';  /*     to dots */
  279.             cdp -= 2;           /*   include leading bracket and dot */
  280.             strcpy(filename, cdp);   /* copy VMS-style path name into global */
  281.             strcat(filename, name);  /* concatenate file name to global */
  282.         }
  283. #else
  284.         strcpy(filename, cdp);  /* Either "" or slash-terminated path */
  285.         strcat(filename, name); /* append file name to path name */
  286. #endif
  287.         free(cdp);
  288.     } else
  289.         strcpy(filename, name); /* copy converted name into global */
  290.  
  291. #if PATH_MAX < (FILNAMSIZ - 1)
  292.     /*
  293.      * Check the length of the file name and truncate if necessary.
  294.      */
  295.     if (PATH_MAX < strlen(filename)) {
  296.         fprintf(stderr, "warning:  filename too long--truncating.\n");
  297.         filename[PATH_MAX] = '\0';
  298.         fprintf(stderr, "[ %s ]\n", filename);
  299.         return (1);             /* 1:  warning error */
  300.     }
  301. #endif
  302.  
  303.     return (0);
  304. }
  305.